Clonamos un repositorio de GitHub, digamos el de requests.

In [1]:
%%bash 
git clone git@github.com:kennethreitz/requests.git ~/code/requests
Cloning into '/home/vterron/code/requests'...

El problema: el desarrollo de requests puede continuar, pero nosotros nos quedamos atrás, usando una versión cada vez más anticuada. ¿Sería posible determinar de forma automática si hay nuevos commits disponibles en GitHub? Veamos:

El último commit en nuestro repositorio actual lo podemos ver con git-describe.

In [2]:
%%bash --out revision
cd ~/code/requests
git describe --long --dirty --tag --always
In [3]:
revision = revision.strip()
print "Revisión:", revision
Revisión: v2.4.3-32-g431282e

Ahora necesitamos ver cuál es el último commit en GitHub - utilizando la API.

Determinamos la URL desde la que el repositorio de clonó:

In [4]:
%%bash --out origen
cd ~/code/requests
git config --get remote.origin.url
In [5]:
print "Origen:", origen
Origen: git@github.com:kennethreitz/requests.git

Para listar los commits en un repositorio tenemos que usar GET /repos/:owner/:repo/commits

Para componer la URL necesitamos, por tanto, saber tanto el usuario como el nombre del repositorio en GitHub del que se clonó nuestro repositorio en GitHub. Eso es fácil a partir de la URL que hemos calculado antes.

In [6]:
 # Match HTTPS and Git clones from GitHub                                                     
REGEXP = "(git@|https://)github\.com(:|/)(?P<username>\w+)/(?P<repository>\w+).git"       

import re
match = re.match(REGEXP, origen)                                                        
username = match.group('username')                                                         
repository = match.group('repository')                                                       
print "username:", username
print "repository:", repository
username: kennethreitz
repository: requests

A partir de estos datos ya podemos componer la URL de la API:

In [7]:
API_URL = "https://api.github.com/repos/{0}/{1}/commits?page=1&per_page=1"
url = API_URL.format(username, repository)
print "API URL:", url
API URL: https://api.github.com/repos/kennethreitz/requests/commits?page=1&per_page=1

Usamos ahora requests para conectarnos y decodificamos el JSON.

In [8]:
import requests

headers = {'User-Agent': 'vterron'}
kwargs = dict(headers=headers, timeout=10)
r = requests.get(url, **kwargs)
data = r.json()
print data
[{u'committer': {u'following_url': u'https://api.github.com/users/Lukasa/following{/other_user}', u'events_url': u'https://api.github.com/users/Lukasa/events{/privacy}', u'organizations_url': u'https://api.github.com/users/Lukasa/orgs', u'url': u'https://api.github.com/users/Lukasa', u'gists_url': u'https://api.github.com/users/Lukasa/gists{/gist_id}', u'html_url': u'https://github.com/Lukasa', u'subscriptions_url': u'https://api.github.com/users/Lukasa/subscriptions', u'avatar_url': u'https://avatars.githubusercontent.com/u/1382556?v=3', u'repos_url': u'https://api.github.com/users/Lukasa/repos', u'received_events_url': u'https://api.github.com/users/Lukasa/received_events', u'gravatar_id': u'', u'starred_url': u'https://api.github.com/users/Lukasa/starred{/owner}{/repo}', u'site_admin': False, u'login': u'Lukasa', u'type': u'User', u'id': 1382556, u'followers_url': u'https://api.github.com/users/Lukasa/followers'}, u'author': {u'following_url': u'https://api.github.com/users/Lukasa/following{/other_user}', u'events_url': u'https://api.github.com/users/Lukasa/events{/privacy}', u'organizations_url': u'https://api.github.com/users/Lukasa/orgs', u'url': u'https://api.github.com/users/Lukasa', u'gists_url': u'https://api.github.com/users/Lukasa/gists{/gist_id}', u'html_url': u'https://github.com/Lukasa', u'subscriptions_url': u'https://api.github.com/users/Lukasa/subscriptions', u'avatar_url': u'https://avatars.githubusercontent.com/u/1382556?v=3', u'repos_url': u'https://api.github.com/users/Lukasa/repos', u'received_events_url': u'https://api.github.com/users/Lukasa/received_events', u'gravatar_id': u'', u'starred_url': u'https://api.github.com/users/Lukasa/starred{/owner}{/repo}', u'site_admin': False, u'login': u'Lukasa', u'type': u'User', u'id': 1382556, u'followers_url': u'https://api.github.com/users/Lukasa/followers'}, u'url': u'https://api.github.com/repos/kennethreitz/requests/commits/3c850b33397b2bdacec3c2c518bc08299e8b8482', u'comments_url': u'https://api.github.com/repos/kennethreitz/requests/commits/3c850b33397b2bdacec3c2c518bc08299e8b8482/comments', u'html_url': u'https://github.com/kennethreitz/requests/commit/3c850b33397b2bdacec3c2c518bc08299e8b8482', u'sha': u'3c850b33397b2bdacec3c2c518bc08299e8b8482', u'parents': [{u'url': u'https://api.github.com/repos/kennethreitz/requests/commits/ab1f493c8b6f82cbf80f8554b5fbbd02f2b2a363', u'sha': u'ab1f493c8b6f82cbf80f8554b5fbbd02f2b2a363', u'html_url': u'https://github.com/kennethreitz/requests/commit/ab1f493c8b6f82cbf80f8554b5fbbd02f2b2a363'}, {u'url': u'https://api.github.com/repos/kennethreitz/requests/commits/d249c0a9c6dccf2bd63c3d1aad365f37cc4591a1', u'sha': u'd249c0a9c6dccf2bd63c3d1aad365f37cc4591a1', u'html_url': u'https://github.com/kennethreitz/requests/commit/d249c0a9c6dccf2bd63c3d1aad365f37cc4591a1'}], u'commit': {u'committer': {u'date': u'2015-05-21T08:16:24Z', u'name': u'Cory Benfield', u'email': u'lukasaoz@gmail.com'}, u'author': {u'date': u'2015-05-21T08:16:24Z', u'name': u'Cory Benfield', u'email': u'lukasaoz@gmail.com'}, u'url': u'https://api.github.com/repos/kennethreitz/requests/git/commits/3c850b33397b2bdacec3c2c518bc08299e8b8482', u'tree': {u'url': u'https://api.github.com/repos/kennethreitz/requests/git/trees/72f2221bc36685bda116cf1fc00b9bcc103eb923', u'sha': u'72f2221bc36685bda116cf1fc00b9bcc103eb923'}, u'comment_count': 0, u'message': u'Merge pull request #2608 from radarhere/patch-1\n\nFixed typos'}}]

El último commit es el primero de todos.

In [9]:
last_commit = data[0]
hash_ = last_commit['sha']
date_str = last_commit['commit']['author']['date']
print "SHA1:", hash_
print "Fecha:", date_str
SHA1: 3c850b33397b2bdacec3c2c518bc08299e8b8482
Fecha: 2015-05-21T08:16:24Z

Podemos obtener el hash corto con git-rev-parse:

In [10]:
%%bash -s "$hash_" --out github_hash  
cd ~/code/requests
git rev-parse --short $1
In [11]:
github_hash = github_hash.strip()
print "SHA1 GitHub:", github_hash
SHA1 GitHub: 3c850b3

La fecha está en formato ISO 8601, YYYY-MM-DDTHH:MM:SSZ (UTC). Lo convertimos a tiempo Unix para poder trabajar fácilmente.

In [13]:
import time
import calendar

fmt = "%Y-%m-%dT%H:%M:%SZ"                                                                   
date_struct = time.strptime(date_str, fmt)                                                   
last_github_date = calendar.timegm(date_struct)
print "Fecha (Unix):", last_github_date
 Fecha (Unix): 1432196184

Si nuestro commit local es el más reciente, el hash de GitHub será una subcadena de la revisión.

In [14]:
print "Revisión", revision
print "SHA1 hash:", github_hash
print github_hash in revision
Revisión v2.4.3-32-g431282e
SHA1 hash: 3c850b3
False

¿Y si son diferentes?

En caso de que sean diferentes, tenemos que comprobar si la fecha del commit local es más reciente que la del último commit el GitHub. Esto lo hacemos porque en caso de que nos adelantemos al repositorio, si estamos trabajando en él, no queremos mostrar ninguna advertencia.

In [15]:
%%bash --out last_commit_date 
cd ~/code/requests
git log -1 --format='%at'
In [16]:
last_commit_date = last_commit_date.strip()
print "Último commit local:", last_commit_date 
Último commit local: 1415391521

Para ver si nuestro último commit es más reciente:

In [17]:
last_commit_date > last_github_date
Out[17]:
True
In [ ]: